package com.example.book.crawler.task;

import com.example.book.common.utils.Constants;
import com.example.book.crawler.BlockingQueues;
import com.example.book.crawler.pageprocessor.CategoryPageProcessor;
import com.example.book.in.entity.BookInfo;
import com.example.book.in.service.BookInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.downloader.HttpClientDownloader;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.proxy.Proxy;
import us.codecraft.webmagic.proxy.SimpleProxyProvider;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@Component
public class BookTask {

    @Autowired
    private BookInfoService bookInfoService;
    @Autowired
    private RedisTemplate redisTemplate;

    private BlockingQueue<Map<String, Object>> queue_catalog = BlockingQueues.getInstanceForCatalog();

    private BlockingQueue<Integer> queue_page = BlockingQueues.getInstanceForPage();

    public BookTask() throws InterruptedException {
    }

    /**
     * 每0 0/10钟执行一次 随机页数
     *
     * @throws InterruptedException
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void takeBook() throws InterruptedException {
        Map<String, Object> catalog = queue_catalog.take();
        Integer page = queue_page.take();

        getInfo(catalog.get("url").toString(), catalog.get("cid").toString(), page);

        queue_catalog.add(catalog);
        queue_page.put(page);
    }

    private void getInfo(String type_url, String category_id, Integer pageNum) throws InterruptedException {
        //目标链接
        String url = type_url + pageNum + ".html";

        List<BookInfo> bookInfoList = new ArrayList<>();

        Spider spider = null;

        Map<String, Object> map = (Map<String, Object>) redisTemplate.opsForList().rightPop(Constants.IP_QUEUE, 2, TimeUnit.SECONDS);
        // 有IP就用IP
        if (map != null) {
            HttpClientDownloader downloader = new HttpClientDownloader();
            downloader.setProxyProvider(SimpleProxyProvider.from(
                    new Proxy(map.get("ip").toString(), Integer.parseInt(map.get("port").toString()))
            ));
            spider = new Spider(new CategoryPageProcessor()).setDownloader(downloader);
        } else {
            spider = new Spider(new CategoryPageProcessor());
        }

        spider.setUUID(UUID.randomUUID().toString()).addUrl(new String[]{url}).addPipeline(
                new Pipeline() {
                    @Override
                    public void process(ResultItems resultItems, Task task) {
                        List<BookInfo> list = (List<BookInfo>) resultItems.get("list");
                        if (list != null) {
                            for (BookInfo bi : list) {
                                BookInfo bookInfo = bookInfoService.get(new BookInfo(category_id, bi.getBookName(), bi.getBookAuthor()));
                                if (bookInfo != null) {
                                    continue;
                                }
                                try {
                                    String filePath = downImg(bi.getBookCover(), category_id);
                                    bi.setBookCover(filePath);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                                bi.setCategoryId(category_id);
                                bookInfoList.add(bi);
                            }
                        }
                    }
                }
        ).thread(1).run();
        spider.clearPipeline().close();

        if (map != null) {
            redisTemplate.opsForList().leftPush(Constants.IP_QUEUE, map);
        }

        // 有值并且 状态不为 -1  才会保存
        if (bookInfoList.size() > 0) {
            bookInfoService.insertBatch(bookInfoList);
        }
    }

    /**
     * 图片链接 加载
     *
     * @param imgUrl
     * @param category_id
     * @return
     * @throws IOException
     */
    private static String downImg(String imgUrl, String category_id) throws IOException {
        URL url = new URL(imgUrl);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(10000);

        DataInputStream dataInputStream = new DataInputStream(connection.getInputStream());

        File fp = new File(File.separator + "home" + File.separator + "book" + File.separator + category_id + File.separator + new SimpleDateFormat("yyyyMMddHHmm").format(new Date()));
        if (!fp.exists()) {
            fp.mkdirs();
        }

        String filePath = fp.getPath() + File.separator + getStrName(imgUrl);

        File file = new File(filePath);

        FileOutputStream fileOutputStream = new FileOutputStream(file);

        byte[] bytes = new byte[1024];
        int length = 0;
        while ((length = dataInputStream.read(bytes)) != -1) {
            fileOutputStream.write(bytes, 0, length);
        }

        dataInputStream.close();
        fileOutputStream.close();
        filePath = filePath.replace(File.separator + "home" + File.separator + "book" + File.separator, "/profile/book/");
        return filePath.replaceAll("\\\\", "/");
    }

    private static String getStrName(String url) {
        String[] strings = url.split("/");
        return strings[strings.length - 1];
    }
}
